//package com.john.bms.config.shiro;
//
//import com.john.bms.listener.ShiroSessionListener;
//import com.john.bms.realm.MyShiroRealm;
//import org.apache.shiro.cache.ehcache.EhCacheManager;
//import org.apache.shiro.codec.Base64;
//import org.apache.shiro.mgt.SecurityManager;
//import org.apache.shiro.session.SessionListener;
//import org.apache.shiro.session.mgt.SessionManager;
//import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
//import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
//import org.apache.shiro.session.mgt.eis.SessionDAO;
//import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
//import org.apache.shiro.spring.LifecycleBeanPostProcessor;
//import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
//import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
//import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
//import org.apache.shiro.web.mgt.CookieRememberMeManager;
//import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
//import org.apache.shiro.web.servlet.SimpleCookie;
//import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
//import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
//import org.springframework.beans.factory.annotation.Qualifier;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//
//import java.util.ArrayList;
//import java.util.Collection;
//import java.util.LinkedHashMap;
//import java.util.Map;
//
//@Configuration
//public class ShiroConfiguration {
//
//    /**
//     * ShiroFilterFactoryBean 处理拦截资源文件问题
//     * 注意：单独一个ShiroFilterFactoryBean配置是或报错的，因为在
//     * 初始化ShiroFilterFactoryBean的时候需要注入：SecurityManager
//     * <p>
//     * Filter Chain定义说明
//     * 1、一个URL可以配置多个Filter，使用逗号分隔
//     * 2、当设置多个过滤器时，全部验证通过，才视为通过
//     * 3、部分过滤器可指定参数，如perms，roles
//     */
//    @Bean(name = "shiroFilterFactoryBean")
//    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager securityManager) {
//
//        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
//        //必须设置 SecurityManager,Shiro的核心安全接口
//        factoryBean.setSecurityManager(securityManager);
//        // 配置访问权限 必须是LinkedHashMap，因为它必须保证有序
//        // 过滤链定义，从上向下顺序执行，一般将 /**放在最为下边 --> : 这是一个坑，一不小心代码就不好使了
//        Map<String, String> filterMap = new LinkedHashMap<>();
//
//        /**
//         * 配置不登录可以访问的资源
//         * authc：该过滤器下的页面必须验证后才能访问，它是Shiro内置的一个拦截器 org.apache.shiro.web.filter.authc.FormAuthenticationFilter
//         * anon：它对应的过滤器里面是空的,什么都没做,可以理解为不拦截
//         * authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
//         */
//        filterMap.put("/login/login", "anon");
//        filterMap.put("/login/info", "anon");
//        filterMap.put("/login/doLogin", "anon");
//        filterMap.put("/404/**", "anon");
//        //logout是shiro提供的过滤器
//        filterMap.put("/logout", "logout");
//        //其他资源都需要认证  authc 表示需要认证才能进行访问 user表示配置记住我或认证通过可以访问的地址
//        filterMap.put("/**", "user");
//        factoryBean.setFilterChainDefinitionMap(filterMap);
//
//        return factoryBean;
//    }
//
//
//    /**
//     * @return
//     * @desc 配置核心安全事务管理器
//     */
//    @Bean(name = "securityManager")
//    public SecurityManager securityManager(@Qualifier("myShiroRealm") MyShiroRealm myShiroRealm) {
//        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//        //配置记住我
//        securityManager.setRememberMeManager(rememberMeManager());
//        // 设置realm
//        securityManager.setRealm(myShiroRealm);
//        //配置自定义session管理，使用ehcache 或redis
//        securityManager.setSessionManager(sessionManager());
//
//        return securityManager;
//    }
//
//    /**
//     * @return
//     * @desc 身份认证realm, 将自己的验证方式加入容器;
//     */
//    @Bean
//    public MyShiroRealm myShiroRealm() {
//        MyShiroRealm realm = new MyShiroRealm();
//        //配置自定义密码比较器
//        realm.setCredentialsMatcher(retryLimitHashedCredentialsMatcher());
//        return realm;
//    }
//
//    /**
//     * cookie对象;会话Cookie模板 ,默认为: JSESSIONID 问题: 与SERVLET容器名冲突,重新定义为sid或rememberMe，自定义
//     *
//     * @return
//     */
//    @Bean
//    public SimpleCookie rememberMeCookie() {
//        //这个参数是cookie的名称，对应前端的checkbox的name = rememberMe
//        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//        //setcookie的httponly属性如果设为true的话，会增加对xss防护的安全系数。它有以下特点：
//        //setcookie()的第七个参数
//        //设为true后，只能通过http访问，javascript无法访问
//        //防止xss读取cookie
//        simpleCookie.setHttpOnly(true);
//        simpleCookie.setPath("/");
//        //<!-- 记住我cookie生效时间30天 ,单位秒;-->
//        simpleCookie.setMaxAge(2592000);
//        return simpleCookie;
//    }
//
//    /**
//     * cookie管理对象;记住我功能,rememberMe管理器
//     *
//     * @return
//     */
//    @Bean
//    public CookieRememberMeManager rememberMeManager() {
//        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
//        cookieRememberMeManager.setCookie(rememberMeCookie());
//        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
//        cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
//        return cookieRememberMeManager;
//    }
//
//    /**
//     * FormAuthenticationFilter 过滤器 过滤记住我
//     *
//     * @return
//     */
//    @Bean
//    public FormAuthenticationFilter formAuthenticationFilter() {
//        FormAuthenticationFilter formAuthenticationFilter = new FormAuthenticationFilter();
//        //对应前端的checkbox的name = rememberMe
//        formAuthenticationFilter.setRememberMeParam("rememberMe");
//        return formAuthenticationFilter;
//    }
//
//    /**
//     * 配置session监听
//     *
//     * @return
//     */
//    @Bean("sessionListener")
//    public ShiroSessionListener sessionListener() {
//        ShiroSessionListener sessionListener = new ShiroSessionListener();
//        return sessionListener;
//    }
//
//    /**
//     * 配置会话ID生成器
//     *
//     * @return
//     */
//    @Bean
//    public SessionIdGenerator sessionIdGenerator() {
//        return new JavaUuidSessionIdGenerator();
//    }
//
//    /**
//     * SessionDAO的作用是为Session提供CRUD并进行持久化的一个shiro组件
//     * MemorySessionDAO 直接在内存中进行会话维护
//     * EnterpriseCacheSessionDAO  提供了缓存功能的会话维护，默认情况下使用MapCache实现，内部使用ConcurrentHashMap保存缓存的会话。
//     *
//     * @return
//     */
//    @Bean
//    public SessionDAO sessionDAO() {
//        EnterpriseCacheSessionDAO enterpriseCacheSessionDAO = new EnterpriseCacheSessionDAO();
//        //使用ehCacheManager
//        enterpriseCacheSessionDAO.setCacheManager(ehCacheManager());
//        //设置session缓存的名字 默认为 shiro-activeSessionCache
//        enterpriseCacheSessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache");
//        //sessionId生成器
//        enterpriseCacheSessionDAO.setSessionIdGenerator(sessionIdGenerator());
//        return enterpriseCacheSessionDAO;
//    }
//
//    /**
//     * 配置保存sessionId的cookie
//     * 注意：这里的cookie 不是上面的记住我 cookie 记住我需要一个cookie session管理 也需要自己的cookie
//     *
//     * @return
//     */
//    @Bean("sessionIdCookie")
//    public SimpleCookie sessionIdCookie() {
//        //这个参数是cookie的名称
//        SimpleCookie simpleCookie = new SimpleCookie("sid");
//        //setcookie的httponly属性如果设为true的话，会增加对xss防护的安全系数。它有以下特点：
//
//        //setcookie()的第七个参数
//        //设为true后，只能通过http访问，javascript无法访问
//        //防止xss读取cookie
//        simpleCookie.setHttpOnly(true);
//        simpleCookie.setPath("/");
//        //maxAge=-1表示浏览器关闭时失效此Cookie
//        simpleCookie.setMaxAge(-1);
//        return simpleCookie;
//    }
//
//    /**
//     * 配置会话管理器，设定会话超时及保存
//     *
//     * @return
//     */
//    @Bean("sessionManager")
//    public SessionManager sessionManager() {
//        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
//        Collection<SessionListener> listeners = new ArrayList<SessionListener>();
//        //配置监听
//        listeners.add(sessionListener());
//        sessionManager.setSessionListeners(listeners);
//        sessionManager.setSessionIdCookie(sessionIdCookie());
//        sessionManager.setSessionDAO(sessionDAO());
//        sessionManager.setCacheManager(ehCacheManager());
//
//        //解决直接关闭浏览器出现的无法注销问题
//        //全局会话超时时间（单位毫秒），默认30分钟  暂时设置为10秒钟 用来测试
//        sessionManager.setGlobalSessionTimeout(1800000);
//        //是否开启删除无效的session对象  默认为true
//        sessionManager.setDeleteInvalidSessions(true);
//        //是否开启定时调度器进行检测过期session 默认为true
//        sessionManager.setSessionValidationSchedulerEnabled(true);
//        //设置session失效的扫描时间, 清理用户直接关闭浏览器造成的孤立会话 默认为 1个小时
//        //设置该属性 就不需要设置 ExecutorServiceSessionValidationScheduler 底层也是默认自动调用ExecutorServiceSessionValidationScheduler
//        //暂时设置为 5秒 用来测试
//        sessionManager.setSessionValidationInterval(1800000);
//        //取消url 后面的 JSESSIONID
//        sessionManager.setSessionIdUrlRewritingEnabled(false);
//
//        return sessionManager;
//    }
//
//    /**
//     * shiro缓存管理器;
//     * 需要添加到securityManager中
//     *
//     * @return
//     */
//    @Bean
//    public EhCacheManager ehCacheManager() {
//        EhCacheManager cacheManager = new EhCacheManager();
//        return cacheManager;
//    }
//
////    /**
////     * 配置shiro redisManager
////     * <p>
////     * 使用的是shiro-redis开源插件
////     *
////     * @return
////     */
////    public RedisManager redisManager() {
////        RedisManager redisManager = new RedisManager();
////        redisManager.setHost("127.0.0.1");
////        redisManager.setPort(6379);
////        // 配置缓存过期时间
////        redisManager.setExpire(1800);
////        redisManager.setTimeout(0);
////        redisManager.setPassword("123");
////        return redisManager;
////    }
////
////
////    /**
////     * RedisSessionDAO shiro sessionDao层的实现 通过redis
////     * <p>
////     * 使用的是shiro-redis开源插件
////     */
////    @Bean
////    public RedisSessionDAO redisSessionDAO() {
////        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
////        redisSessionDAO.setRedisManager(redisManager());
////        return redisSessionDAO;
////    }
//
//    /**
//     * 配置Shiro生命周期处理器
//     *
//     * @return
//     */
//    @Bean(name = "lifecycleBeanPostProcessor")
//    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
//        return new LifecycleBeanPostProcessor();
//    }
//
//    /**
//     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
//     * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
//     *
//     * @return
//     */
//    @Bean
//    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
//        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
//        creator.setProxyTargetClass(true);
//        return creator;
//    }
//
//    /**
//     * 开启shiro 注解模式
//     * 可以在controller中的方法前加上注解
//     * 如 @RequiresPermissions("userInfo:add")
//     *
//     * @param securityManager
//     * @return
//     */
//    @Bean
//    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
//        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
//        advisor.setSecurityManager(securityManager);
//        return advisor;
//    }
//
//    /**
//     * 配置密码比较器
//     *
//     * @return
//     */
//    @Bean("credentialsMatcher")
//    public RetryLimitHashedCredentialsMatcher retryLimitHashedCredentialsMatcher() {
//        RetryLimitHashedCredentialsMatcher retryLimitHashedCredentialsMatcher = new RetryLimitHashedCredentialsMatcher(ehCacheManager());
//
//        //如果密码加密,可以打开下面配置
//        //加密算法的名称
//        //retryLimitHashedCredentialsMatcher.setHashAlgorithmName("MD5");
//        //配置加密的次数
//        //retryLimitHashedCredentialsMatcher.setHashIterations(1024);
//        //是否存储为16进制
//        //retryLimitHashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
//
//        return retryLimitHashedCredentialsMatcher;
//    }
//
//    /*
//     * 1.LifecycleBeanPostProcessor，这是个DestructionAwareBeanPostProcessor的子类，负责org.
//     * apache.shiro.util.Initializable类型bean的生命周期的，初始化和销毁。主要是AuthorizingRealm类的子类，
//     * 以及EhCacheManager类。
//     * 2.HashedCredentialsMatcher，这个类是为了对密码进行编码的，防止密码在数据库里明码保存，当然在登陆认证的生活，
//     * 这个类也负责对form里输入的密码进行编码。
//     * 3.ShiroRealm，这是个自定义的认证类，继承自AuthorizingRealm，负责用户的认证和权限的处理，可以参考JdbcRealm的实现。
//     * 4.EhCacheManager，缓存管理，用户登陆成功后，把用户信息和权限信息缓存起来，然后每次用户请求时，放入用户的session中，
//     * 如果不设置这个bean，每个请求都会查询一次数据库。
//     * 5.SecurityManager，权限管理，这个类组合了登陆，登出，权限，session的处理，是个比较重要的类。
//     * 6.ShiroFilterFactoryBean，是个factorybean，为了生成ShiroFilter。它主要保持了三项数据，
//     * securityManager，filters，filterChainDefinitionManager。
//     * 7.DefaultAdvisorAutoProxyCreator，Spring的一个bean，由Advisor决定对哪些类的方法进行AOP代理。
//     * 8.AuthorizationAttributeSourceAdvisor，shiro里实现的Advisor类，
//     * 内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。
//     */
//
//}
